/***************************************************************************
 *   Copyright (C) 2008 by Philipp Müller <philipp.mueller@gmx.de>         *
 *   Copyright (C) 2008 by Tanguy Krotoff <tkrotoff@gmail.com>             *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
 ***************************************************************************/

#include <QtGui>

#include <phonon/audiooutput.h>

#include "widgetplayvideo.h"
#include "qtvomp.h"
#include "vompglobal.h"

WidgetPlayVideo::WidgetPlayVideo( MainWindow* mainWindow, VDR* vdr, QWidget *parent ) : QWidget( parent ),
    m_mainWindow( mainWindow ),
    m_vdr( vdr ),
    m_exit( false ),
    m_startPlaying( false ),
    m_switchChannel( false )
{
}


WidgetPlayVideo::~WidgetPlayVideo()
{
}


void WidgetPlayVideo::initWidgetPlayVideo()
{
    qDebug() << "WidgetPlayVideo::initWidgetPlayVideo called";

    m_exit = false;
    m_startPlaying = false;

    m_mediaObject = new Phonon::MediaObject( this );
    m_mediaObject->setTickInterval( 1000 );

    setupActions();
    setupUi();

    Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput( Phonon::VideoCategory, this );
    Phonon::createPath( m_mediaObject, audioOutput );
    Phonon::createPath( m_mediaObject, m_videoWidget );

    m_volumeSlider->setAudioOutput( audioOutput );

    connect( m_mediaObject, SIGNAL( stateChanged( Phonon::State, Phonon::State ) ),
             this,          SLOT( stateChanged( Phonon::State, Phonon::State ) ) );
    connect( m_mediaObject, SIGNAL( stateChanged( Phonon::State, Phonon::State ) ),
             this,          SLOT( metaStateChanged( Phonon::State, Phonon::State ) ) );
}


void WidgetPlayVideo::stateChanged( Phonon::State newState, Phonon::State /* oldState */ )
{
    switch ( newState )
    {

        case Phonon::ErrorState:
            qDebug() << "WidgetPlayVideo::stateChanged: New State = error";

            if ( m_mediaObject->errorType() == Phonon::FatalError )
            {
                QMessageBox::warning( this, tr( "Fatal Error" ), m_mediaObject->errorString() );
            }
            else
            {
                QMessageBox::warning( this, tr( "Error" ), m_mediaObject->errorString() );
            }

            exit();

            return;

        case Phonon::StoppedState:

            if ( !m_exit && m_switchChannel )
            {
                qDebug() << "WidgetPlayVideo::stateChanged: newState = Stop and we change channel";
                switchChannel();
                return;
            }
            else
                if ( m_exit )
                {
                    qDebug() << "WidgetPlayVideo::stateChanged: newState = Stop and we exit";
                    exit();
                    return;
                }
                else
                {
                    qDebug() << "WidgetPlayVideo::stateChanged: New State = stopped";
                    if ( m_ioStream->streamType() == STREAM_TV )
                    {
                        //We entered stop state, most propabely due to channel not available anymore
                        m_videoWidget->hide();
                        m_channelNotAvailable->show();
                    }
                    m_playAction->setEnabled( true );
                    m_pauseAction->setEnabled( false );
                    m_stopAction->setEnabled( false );
//                 m_timeLcd->display("00:00");
                    break;
                }

        case Phonon::PlayingState:

            qDebug() << "WidgetPlayVideo::stateChanged: New State = playing";
            m_startPlaying = false;
            m_playAction->setEnabled( false );
            m_pauseAction->setEnabled( true );
            m_stopAction->setEnabled( true );
            break;

        case Phonon::PausedState:
            qDebug() << "WidgetPlayVideo::stateChanged: New State = paused";
            m_playAction->setEnabled( true );
            m_pauseAction->setEnabled( false );
            m_stopAction->setEnabled( true );
            break;

        case Phonon::BufferingState:
            qDebug() << "WidgetPlayVideo::stateChanged: New State = buffering";
            //FIXME Hack: Recordings are not going into playing state, so let's reactivate the buttons already in buffering state
            //When Phonon is fixed, we remove it again.

            if ( m_ioStream->streamType() == STREAM_RECORDING )
            {
                m_playAction->setEnabled( false );
                m_pauseAction->setEnabled( true );
                m_stopAction->setEnabled( true );
            }

            break;

        default:
            qDebug() << "WidgetPlayVideo::stateChanged: New State = default/unknown";
    }
}


void WidgetPlayVideo::metaStateChanged( Phonon::State newState, Phonon::State /* oldState */ )
{
    qDebug() << "WidgetPlayVideo::metaStateChanged called";

    if ( newState == Phonon::ErrorState )
    {
        // We already get an error message from stateChanged
        // QMessageBox::warning( this, tr("Error opening files"), m_mediaObject->errorString() );
        m_startPlaying = false;
        return;
    }

    if ( newState != Phonon::StoppedState && newState != Phonon::PausedState )
    {
#ifdef NETWORK_DEBUG
        qDebug() << "WidgetPlayVideo::metaStateChanged state is not stopped or paused";
#endif
        return;
    }

    if ( m_mediaObject->currentSource().type() == Phonon::MediaSource::Invalid )
    {
        qDebug() << "WidgetPlayVideo::metaStateChanged type is invalid";
        return;
    }

    QMap<QString, QString> metaData = m_mediaObject->metaData();

    QString title = metaData.value( "TITLE" );

    if ( title == "" )
    {
        title = m_mediaObject->currentSource().fileName();
    }

    m_titelText->setText( title );

    m_artistText->setText( metaData.value( "ARTIST" ) );
    m_albumText->setText( metaData.value( "ALBUM" ) );
    m_yearText->setText( metaData.value( "DATE" ) );

    m_genreText->setText( metaData.value( "GENRE" ) );
    m_trackText->setText( metaData.value( "TRACKNUMBER" ) );
    m_descriptionText->setText( metaData.value( "DESCRIPTION" ) );
    //Now we can start playing

    if ( m_startPlaying )
    {
        m_startPlaying = false;
        m_mediaObject->play();
    }
}


void WidgetPlayVideo::setupActions()
{
    m_playAction = new QAction( style()->standardIcon( QStyle::SP_MediaPlay ), tr( "Play" ), this );
    m_playAction->setShortcut( tr( "Crl+P" ) );
    m_playAction->setDisabled( true );
    m_pauseAction = new QAction( style()->standardIcon( QStyle::SP_MediaPause ), tr( "Pause" ), this );
    m_pauseAction->setShortcut( tr( "Ctrl+A" ) );
    m_pauseAction->setDisabled( true );
    m_stopAction = new QAction( style()->standardIcon( QStyle::SP_MediaStop ), tr( "Stop" ), this );
    m_stopAction->setShortcut( tr( "Ctrl+S" ) );
    m_stopAction->setDisabled( true );

    m_fullScreen = new QAction( QIcon( ":/images/view-fullscreen.png" ), tr( "Fullscreen" ), this );
    m_fullScreen->setShortcut( tr( "Alt+Enter" ) );
    m_fullScreen->setDisabled( false );

    connect( m_playAction,  SIGNAL( triggered() ), m_mediaObject, SLOT( play() ) );
    connect( m_pauseAction, SIGNAL( triggered() ), m_mediaObject, SLOT( pause() ) );
    connect( m_stopAction,  SIGNAL( triggered() ), m_mediaObject, SLOT( stop() ) );

    connect( m_fullScreen,  SIGNAL( triggered() ), this, SLOT( fullScreenAction() ) );
}


void WidgetPlayVideo::setupUi()
{
    QVBoxLayout *vBox;
    QHBoxLayout *hBox1;
    QHBoxLayout *hBox2;

    vBox = new QVBoxLayout( this );
    hBox1 = new QHBoxLayout();
    hBox2 = new QHBoxLayout();

    m_videoWidget = new WidgetVideo( this );
    m_osd = new WidgetOsd( m_videoWidget );
    m_metaDataWidget = new QWidget( this );

    //Meta data widget
    m_titelLabel       = new QLabel( "Titel" );
    m_artistLabel      = new QLabel( "Artist" );
    m_albumLabel       = new QLabel( "Album" );
    m_yearLabel        = new QLabel( "Year" );

    m_genreLabel       = new QLabel( "Genre" );
    m_trackLabel       = new QLabel( "TrackID" );
    m_descriptionLabel = new QLabel( "Description" );

    m_titelText  = new QLabel( "-" );
    m_titelText->setFrameStyle( QFrame::Box );
    m_titelText->setMargin( 4 );

    m_artistText = new QLabel( "-" );
    m_artistText->setFrameStyle( QFrame::Box );
    m_artistText->setMargin( 4 );

    m_albumText  = new QLabel( "-" );
    m_albumText->setFrameStyle( QFrame::Box );
    m_albumText->setMargin( 4 );

    m_yearText   = new QLabel( "-" );
    m_yearText->setFrameStyle( QFrame::Box );
    m_yearText->setMargin( 4 );

    m_genreText  = new QLabel( "-" );
    m_genreText->setFrameStyle( QFrame::Box );
    m_genreText->setMargin( 4 );

    m_trackText  = new QLabel( "-" );
    m_trackText->setFrameStyle( QFrame::Box );
    m_trackText->setMargin( 4 );

    m_descriptionText  = new QLabel( "-" );
    m_descriptionText->setFrameStyle( QFrame::Box );
    m_descriptionText->setMargin( 4 );

    QHBoxLayout *IDLayout1 = new QHBoxLayout;

    QVBoxLayout *entryLayout1 = new QVBoxLayout;
    entryLayout1->addWidget( m_titelLabel );
    entryLayout1->addWidget( m_titelText );

    QVBoxLayout *entryLayout2 = new QVBoxLayout;
    entryLayout2->addWidget( m_artistLabel );
    entryLayout2->addWidget( m_artistText );

    QVBoxLayout *entryLayout3 = new QVBoxLayout;
    entryLayout3->addWidget( m_albumLabel );
    entryLayout3->addWidget( m_albumText );

    QVBoxLayout *entryLayout4 = new QVBoxLayout;
    entryLayout4->addWidget( m_yearLabel );
    entryLayout4->addWidget( m_yearText );

    IDLayout1->addLayout( entryLayout1 );
    IDLayout1->addLayout( entryLayout2 );
    IDLayout1->addLayout( entryLayout3 );
    IDLayout1->addLayout( entryLayout4 );

    QHBoxLayout *IDLayout2 = new QHBoxLayout;

    QVBoxLayout *entryLayout5 = new QVBoxLayout;
    entryLayout5->addWidget( m_genreLabel );
    entryLayout5->addWidget( m_genreText );

    QVBoxLayout *entryLayout6 = new QVBoxLayout;
    entryLayout6->addWidget( m_trackLabel );
    entryLayout6->addWidget( m_trackText );

    QVBoxLayout *entryLayout7 = new QVBoxLayout;
    entryLayout7->addWidget( m_descriptionLabel );
    entryLayout7->addWidget( m_descriptionText );

    IDLayout2->addLayout( entryLayout5 );
    IDLayout2->addLayout( entryLayout6 );
    IDLayout2->addLayout( entryLayout7 );

    QVBoxLayout *metaDataWidgetLayout = new QVBoxLayout;
    metaDataWidgetLayout->addLayout( IDLayout1 );
    metaDataWidgetLayout->addLayout( IDLayout2 );
    metaDataWidgetLayout->addStretch();
    m_metaDataWidget->setLayout( metaDataWidgetLayout );

    // Toolbar
    m_mediaButtonBar = new QToolBar;

    m_mediaButtonBar->addAction( m_playAction );
    m_mediaButtonBar->addAction( m_pauseAction );
    m_mediaButtonBar->addAction( m_stopAction );

    QPushButton* backButtonVideo = new QPushButton( tr( "Back" ), this );
    backButtonVideo->setIcon( style()->standardIcon( QStyle::QStyle::SP_ArrowLeft ) );

    m_seekSlider = new Phonon::SeekSlider( this );
    m_seekSlider->setMediaObject( m_mediaObject );
    m_seekSlider->setSingleStep( 10 * 1000 /* 10s */ );
    m_seekSlider->setPageStep( 60 * 1000 /* 1min */ );

    m_volumeSlider = new Phonon::VolumeSlider( this );
    m_volumeSlider->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum );

    QToolBar *barFullScreen = new QToolBar;
    barFullScreen->addAction( m_fullScreen );

    //"Channel not available" widget
    m_channelNotAvailable = new QLabel( tr( "Channel not available" ), this );
    m_channelNotAvailable->setAlignment( Qt::AlignCenter );
    m_channelNotAvailable->setAutoFillBackground( true );
    m_channelNotAvailable->setPalette( QPalette( Qt::black ) );
    m_channelNotAvailable->hide();
    vBox->addWidget( m_channelNotAvailable );

    //Videowidget
    hBox1->addWidget( m_videoWidget );
    vBox->addLayout( hBox1 );
    vBox->addWidget( m_metaDataWidget );

    //Control area
    hBox2->addWidget( backButtonVideo );
    hBox2->addWidget( m_mediaButtonBar );
    hBox2->addStretch();
    hBox2->addWidget( m_seekSlider );
    hBox2->addWidget( m_volumeSlider );
    hBox2->addWidget( barFullScreen );
    vBox->addLayout( hBox2 );

    connect( backButtonVideo,  SIGNAL( clicked() ),
             this,             SLOT( stopPlayVideo() ) );
    connect( this,             SIGNAL( setFullScreen( bool ) ),
             m_videoWidget,    SLOT( setFullScreen( bool ) ) );
    connect( this,             SIGNAL( hideWindowTV( bool ) ),
             m_mainWindow,     SLOT( displayChannelsTV( bool ) ) );
    connect( this,             SIGNAL( hideWindowRecording( bool ) ),
             m_mainWindow,     SLOT( displayRecordings( bool ) ) );
    connect( this,             SIGNAL( hideWindowMedia( bool ) ),
             m_mainWindow,     SLOT( displayMediaList( bool ) ) );
}


void WidgetPlayVideo::playTV()
{
    qDebug() << "WidgetPlayVideo::playTV: was called";
    m_exit = false;

    QModelIndexList selectionList = m_mainWindow->channelListSelectionModel()->selectedRows();

    if ( selectionList.size() != 1 )
    {
        qWarning() << "playTV: Wrong selection list size: " << selectionList.size();
        return;
    }

    quint32 channel = selectionList[ 0 ].data( ChannelListModel::ChannelNumberRole ).toInt();

    if ( channel == 0 )
    {
        qWarning() << "WidgetPlayVideo::playTV: entry is wrong -> return";
        return;
    }

    m_ioStream = new IOStream( QString(), channel, m_vdr, STREAM_TV, this );
    m_ioStream->setObjectName( "Channel_" + channel );

    m_seekSlider->hide();
    m_mediaButtonBar->hide();
    m_metaDataWidget->hide();

    if( m_ioStream->streamStarted() )
    {

        qDebug() << "WidgetPlayVideo::playTV let's enqueue the stream";

        m_ioStream->waitForReadyRead( 2000 );
        m_mediaObject->setCurrentSource( m_ioStream );

        qDebug() << "WidgetPlayVideo::playTV enqueue done, now lets play";

        m_mediaObject->play();

        m_videoWidget->show();
        m_channelNotAvailable->hide();
    }
    else
    {
        qDebug() << "WidgetPlayVideo::playTV stream not started, so show 'Channal unavaiable'";

        m_videoWidget->hide();
        m_channelNotAvailable->show();
    }

    m_mainWindow->centralWidget()->setCurrentIndex( MainWindow::WIDGET_PLAYVIDEO );
    setFocus( Qt::OtherFocusReason );

    m_osd->showOsdTv( selectionList[ 0 ] );
}


void WidgetPlayVideo::playRecording()
{
    qDebug() << "WidgetPlayVideo::playRecording: was called";

    m_exit = false;

    RecordingsWidgetItem* recordingItem = static_cast<RecordingsWidgetItem*>( m_mainWindow->recordingsList()->currentItem() );
    int type = recordingItem->entryType();

    if ( type != REC_TYPE_FILE )
    {
        qDebug() << "WidgetPlayVideo::playRecording: entry is not a file -> return";
        return;
    }

    qDebug() << "WidgetPlayVideo::playRecording: make instance of stream for entry " << recordingItem->entryName()

    << "  with path: " << recordingItem->path();

    m_ioStream = new IOStream( recordingItem->path(), 0, m_vdr, STREAM_RECORDING, this );
    m_ioStream->setObjectName( recordingItem->path() );

    m_mediaObject->setCurrentSource( m_ioStream );

    m_mediaObject->play();

    m_mediaButtonBar->show();
    m_seekSlider->show();

    m_videoWidget->show();
    m_channelNotAvailable->hide();
    m_metaDataWidget->hide();

    m_mainWindow->centralWidget()->setCurrentIndex( MainWindow::WIDGET_PLAYVIDEO );
    setFocus( Qt::OtherFocusReason );

    m_osd->showOsdRecording( recordingItem );
}


void WidgetPlayVideo::playMedia()
{
    qDebug() << "WidgetPlayVideo::playMedia: was called";

    m_exit = false;

    MediaWidgetItem* mediaItem = static_cast<MediaWidgetItem*>( m_mainWindow->mediaList()->currentItem() );
    int type = mediaItem->entryType();

    if ( type == MEDIA_TYPE_DIR || type == MEDIA_TYPE_UNKNOWN )
    {
        qDebug() << "MainWindow::playMedia: entry is a directory or type unknown -> return";
        return;
    }

    m_ioStream = new IOStream( mediaItem->path(), 0, m_vdr, STREAM_MEDIA, this );
    m_ioStream->setObjectName( m_mainWindow->mediaList()->currentItem()->text( 0 ) );

    m_mediaObject->setCurrentSource( m_ioStream );
    //We don't start playing now, as we first want to get meta data. We start playing in metadatachanged.
    m_startPlaying = true;

    m_videoWidget->hide();
    m_channelNotAvailable->hide();
    m_metaDataWidget->show();
    m_mediaButtonBar->show();
    m_seekSlider->show();

    m_mainWindow->centralWidget()->setCurrentIndex( MainWindow::WIDGET_PLAYVIDEO );

    setFocus( Qt::OtherFocusReason );
}


void WidgetPlayVideo::exit()
{
    qDebug() << "WidgetPlayVideo::exit called";
    m_mediaObject->clearQueue();
    delete m_ioStream;

    switch ( m_ioStream->streamType() )
    {

        case STREAM_TV:
            emit hideWindowTV( false );
            return;

        case STREAM_RECORDING:
            emit hideWindowRecording( false );
            return;

        case STREAM_MEDIA:
            emit hideWindowMedia( false );
            return;

        default:
            qWarning() << "WidgetPlayVideo::stateChanged: Unknown streamType!";
            return;
    }
}


void WidgetPlayVideo::switchChannel()
{
    m_mediaObject->clearQueue();
    delete m_ioStream;
    m_switchChannel = false;
    m_videoWidget->show();
    m_channelNotAvailable->hide();
    playTV();
}


void WidgetPlayVideo::stopPlayVideo()
{
    qDebug() << "WidgetPlayVideo::stopPlayVideo: was called";
    m_osd->timer()->stop();
    m_osd->hide();

    if ( m_mediaObject->state() == Phonon::StoppedState )
    {
        exit();
    }
    else
    {
        m_exit = true;
        m_mediaObject->stop();
    }

    qDebug() << "WidgetPlayVideo::stopPlayVideo: has ended";
}


void WidgetPlayVideo::fullScreenAction()
{
    emit setFullScreen( !isFullScreen() );
}


void WidgetPlayVideo::keyPressEvent( QKeyEvent * event )
{
    handleKeyPressEvent( event );
    QWidget::keyPressEvent( event );
}


void WidgetPlayVideo::handleKeyPressEvent( QKeyEvent * event )
{
    switch ( event->key() )
    {

        case Qt::Key_PageUp:
        {
            if ( m_ioStream->streamType() == STREAM_TV )
            {
                QModelIndexList selectionList = m_mainWindow->channelListSelectionModel()->selectedRows();

                if ( selectionList.size() != 1 )
                {
                    qWarning() << "WidgetPlayVideo::handleKeyPressEvent: Wrong selection list size: " << selectionList.size();
                    return;
                }

                qDebug() << "WidgetPlayVideo::keyPressEvent: key Up";

                int currentRow = selectionList[ 0 ].row();

                if ( currentRow == m_mainWindow->channelListView()->model()->rowCount() - 1 )
                {
                    currentRow = 0;
                }
                else
                {
                    currentRow++;
                }

                //I'm sure following can be done more directly...
                m_mainWindow->channelListSelectionModel()->select( m_mainWindow->channelListView()->model()->index( currentRow, 0 ), QItemSelectionModel::ClearAndSelect );

                if( m_mediaObject->state() == Phonon::StoppedState )
                {
                    //Where don't have a stream, so "channel is not available" state
                    switchChannel();
                }
                else
                {
                    m_switchChannel = true;

                    m_mediaObject->stop();
                }

                event->accept();

                return;
            }
        }

        case Qt::Key_PageDown:
        {
            if ( m_ioStream->streamType() == STREAM_TV )
            {

                QModelIndexList selectionList = m_mainWindow->channelListSelectionModel()->selectedRows();

                if ( selectionList.size() != 1 )
                {
                    qWarning() << "WidgetPlayVideo::handleKeyPressEvent: Wrong selection list size: " << selectionList.size();
                    return;
                }

                qDebug() << "WidgetPlayVideo::keyPressEvent: key Down";

                int currentRow = selectionList[ 0 ].row();

                if ( currentRow == 0 )
                {
                    currentRow = m_mainWindow->channelListView()->model()->rowCount() - 1;
                }
                else
                {
                    currentRow--;
                }

                //I'm sure following can be done more directly...
                m_mainWindow->channelListSelectionModel()->select( m_mainWindow->channelListView()->model()->index( currentRow, 0 ), QItemSelectionModel::ClearAndSelect );

                if( m_mediaObject->state() == Phonon::StoppedState )
                {
                    //Where don't have a stream, so "channel is not available" state
                    switchChannel();
                }
                else
                {
                    m_switchChannel = true;

                    m_mediaObject->stop();
                }

                event->accept();

                return;
            }
        }

        case Qt::Key_Escape:
        {
            if ( m_videoWidget->isFullScreen() )
            {
                qDebug() << "MyVideoWidget::keyPressEvent: Escape";
                emit setFullScreen( false );
                event->accept();
                return;
            }
        }
    }
}
